package me.chan.chatting.server.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import me.chan.chatting.server.config.ApplicationConfig;
import me.chan.chatting.server.msg.ChatRequestMessage;
import me.chan.chatting.server.msg.LoginRequestMessage;
import me.chan.chatting.server.msg.Message;
import me.chan.chatting.server.serialize.SerializeAlgo;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

@ChannelHandler.Sharable
@Slf4j
public class SharableMessageCodec extends MessageToMessageCodec<ByteBuf, Message> {

    private static final String MAGIC_NUMBER = "CXJR";

    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> out) throws Exception {

        ByteBuf buff = ctx.alloc().buffer();
        // magic number  4B
        buff.writeBytes(MAGIC_NUMBER.getBytes());
        // version   1B
        buff.writeByte(0x01);
        // serialize algo 1B
        buff.writeByte(ApplicationConfig.getSerializeAlgo().getSerial());
        // business related command 1B
        buff.writeByte(msg.getMessageType());
        // sequenceId  4B
        buff.writeInt(msg.getSequenceId());
        // nonsense  1B
        buff.writeByte(0xff);
        // content length 4B
        SerializeAlgo algo = ApplicationConfig.getSerializeAlgo();
        byte[] content = algo.serialize(msg);
        buff.writeInt(content.length);
        // content
        buff.writeBytes(content);
        out.add(buff);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        int magicNumber = msg.readInt();
        int version = msg.readByte();
        int serializeAlgo = msg.readByte();
        int msgType = msg.readByte();
        int sequenceId = msg.readInt();
        msg.readByte();
        int length = msg.readInt();
        byte[] content = new byte[length];
        msg.readBytes(content, 0, length);
        SerializeAlgo algo = ApplicationConfig.getSerializeAlgo();
        Message message = algo.deserialize(Message.class, content);
        log.debug("{}, {}, {}, {}, {}, {}",
                magicNumber, version, serializeAlgo, msgType, sequenceId, length);
        System.out.println();
        log.debug("{}", message);
        out.add(message);
    }


    public static void main(String[] args) {
        EmbeddedChannel channel = new EmbeddedChannel(
                new LoggingHandler(LogLevel.DEBUG),
                new LengthFieldBasedFrameDecoder(
                        1024, 12, 4, 0, 0),
                new SharableMessageCodec()

        );

        // FIXME messageType is incorrect
        ChatRequestMessage msg = new ChatRequestMessage("xiaoming", "xiaohong","I love you");
        // encode
         channel.writeOutbound(msg);

        // decode
         channel.writeInbound(msg);
    }
}
